﻿using GamFi.API.Application.Exceptions;
using GamFi.API.Application.Interfaces;
using GamFi.API.Application.Resources;
using GamFi.API.Domain.Entities;
using MediatR;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Localization;

namespace GamFi.API.Application.Features.Queries.Wallet.PostChangeBalance;

public class PostChangeBalanceCommandHandler(
    IDbContext dbContext,
    IUserContext userContext,
    IStringLocalizer<ExceptionMessages> localizer) : IRequestHandler<PostChangeBalanceCommand, bool>
{
    public async Task<bool> Handle(PostChangeBalanceCommand request, CancellationToken cancellationToken)
    {
        if (request is null)
            throw new RequestException(localizer[nameof(RequestException.RequestIsEmpty)]);

        if (userContext.CurrentUserId is null)
            throw new UserException(localizer[nameof(UserException.PermissionDenied)]);

        var walletFromDb = await dbContext.Wallets
            .FirstOrDefaultAsync(w => w.UserId == userContext.CurrentUserId, cancellationToken);

        if (walletFromDb is null)
            throw new WalletException(localizer[nameof(WalletException.WalletNotFound)]);

        var oldBalace = walletFromDb.Balance;

        switch (request.Operation)
        {
            case "deposit":
                walletFromDb.Balance += request.Amount;
                break;
            case "withdraw":
                walletFromDb.Balance -= request.Amount;
                break;
            default:
                throw new WalletException(localizer[nameof(WalletException.OperationNotExist)]);
        }

        if (walletFromDb.Balance < 0)
            walletFromDb.Balance = 0;

        var newBalance = walletFromDb.Balance;

        var transaction = new Transaction
        {
            Amount = Math.Abs(oldBalace - newBalance),
            Date = DateTime.UtcNow,
            Operation = request.Operation
        };

        if (walletFromDb.Transactions != null)
            walletFromDb.Transactions.Add(transaction);
        else
            walletFromDb.Transactions = [transaction];

        await dbContext.Transactions.AddAsync(transaction, cancellationToken);
        await dbContext.SaveChangesAsync(cancellationToken);
        return true;
    }
}